<?php

/**
 *
 * @property  string $__version
 * @property  string $__device
 * @property  string $__method
 *
 */

class Request {
  protected static $instance;
	//protected static $singleton_flag;
	protected static $headers;
	protected static $params = array();
	protected static $path = array();

  private $isManhattan;

	public function __construct() {
		if (isset(self::$instance) && !IS_CLI) {
			throw new Exception("Only allow single request instance in each request");
		}

		self::$instance = $this;

		$this->init();

		self::$path = explode('/', trim($this->uri(), '/'));

		//update request
		foreach (array_merge($_GET, $_POST) as $k => $v) {
			$this->$k = $v;
		}
	}

  public static function instance() {
    return self::$instance;
  }

	private function init() {
		$_REQUEST = array();	//出于安全和严谨的考虑
		$_GET = $this->formatInput($_GET);
		$_POST = $this->formatInput($_POST);

		if (!isset($_SERVER['SCRIPT_URL'])) {
			$_SERVER['SCRIPT_URL'] = ($pos = strpos($_SERVER['REQUEST_URI'], '?')) === false ?
				$_SERVER['REQUEST_URI'] :
				substr($_SERVER['REQUEST_URI'], 0, $pos);
		}

		if (!isset($_SERVER['HTTP_HOST'])) {
			$_SERVER['HTTP_HOST'] = 'host';
		}

    	$scheme = $this->isHttps() ? 'https' : 'http';

		//$_GET过滤掉了不安全字符, 但是预定义变量里面还可能存在
		$_SERVER['QUERY_STRING'] = http_build_query($_GET);
		$_SERVER['REQUEST_URI'] = $_SERVER['SCRIPT_URL'] . ($_GET ? '?' . $_SERVER['QUERY_STRING'] : '');
	}

  public function setPath($path) {
    self::$path = explode('/', trim($path, '/'));
  }

  /*
	public function header($key = null) {
		if (is_null(self::$headers)) self::$headers = getallheaders();
		return $key
			? (isset(self::$headers[$key]) ? self::$headers[$key] : '')
			: self::$headers;
	}*/

	//how about use static function instead?
	public function host() {
		return $_SERVER['HTTP_HOST'];
	}

	public function referer() {
		return (isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '');
	}

	public function ua() {
		return (isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '');
	}

	public function uri() {
		return $_SERVER['SCRIPT_URL'];
	}

	public function url() {
		//return $_SERVER['SCRIPT_URI'];
	}

  public function isHttps() {
	return (isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) == 'on');
  }

	public function path($offset = null) {
		if (is_null($offset)) {
			return self::$path;
		} else {
			return isset(self::$path[$offset]) ? self::$path[$offset] : null;
		}
	}

	public function post($name = null, $default = null) {
		return is_null($name) ? $_POST : (isset($_POST[$name]) ? $_POST[$name] : $default);
	}

	public function get($name = null, $default = null) {
		return is_null($name) ? $_GET : (isset($_GET[$name]) ? $_GET[$name] : $default);
	}

	public function cookie($name = null, $default = null) {
		return is_null($name) ? $_COOKIE : (isset($_COOKIE[$name]) ? $_COOKIE[$name] : $default);
	}

	public function method() {
		if ($this->__method) return strtolower($this->__method);
		return isset($_SERVER['REQUEST_METHOD']) ? strtolower($_SERVER['REQUEST_METHOD']) : '';
	}

	public function isGet() {
		return $this->method() == 'get';
	}

	public function isPost() {
		return $this->method() == 'post';
	}

	public function isPut() {
		return $this->method() == 'put';
	}

	public function isDelete() {
		return $this->method() == 'delete';
	}

  public function isIOS() {
    return strpos(strtolower($this->_device), 'matcha') !== false;
  }

  public function isAndroid() {
    return strpos(strtolower($this->_device), 'android') !== false;
  }

  public function is3x() {
    return strpos($this->_device, 'iPhone 6') !== false;
  }

  public function isManhattan() {
    return intval($this->isManhattan);
  }

	public function isMobile() {
		if ( isset($_SERVER['HTTP_VIA'])
			&& preg_match('/wap/i', $_SERVER['HTTP_VIA'])) {
			return true;
		}
		$pattern = '/(nokia|sony|samsung|ppc|symbian|midp|ucweb|blackberry|android|Windows Phone OS)/i';
		return preg_match($pattern, $this->ua());
	}

	public function __set($name, $value) {
		self::$params[$name] = $value;
		if (is_null($value)) unset(self::$params[$name]);
	}

	public function __get($name) {
		return isset(self::$params[$name]) ? self::$params[$name] : null;
	}

	public function params() {
		return self::$params;
	}

	private function formatInput($data) {
		if (is_array($data)) {
			$arr = array();
			foreach($data as $k => $v) {
				$arr[$this->formatInput($k)] = $this->formatInput($v);
			}
			unset($arr['']); //key被替换成空的滤掉
			return array_filter($arr, function($v) {
				if(is_string($v)) {
					return strlen($v) > 0;
				} else {
					return !empty($v);
				}
			});
		} else {
			return trim(stripslashes($data));
		}
	}
}